#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <pimstore.h>

#include <windows.h>
#include <aygshell.h>
#include <cemapi.h>
#include <mapiutil.h>

#ifdef _WIN32_WCE
#pragma comment(lib,"cemapi.lib")
#pragma comment(lib,"UUID.lib")
#endif

#define RELEASE(s)  \
	if (s != NULL)  \
	{               \
	s->Release();   \
	s = NULL;       \
	}


void CopyString(LPTSTR szDest,LPCTSTR szSrc,int nMaxLength)
{
	int nSrcLen=(int)_tcslen(szSrc)+1;
	int nLen=min(nSrcLen,nMaxLength);
	memcpy(szDest,szSrc,sizeof(TCHAR)*nLen);
	if(nLen==nMaxLength) szDest[nMaxLength-1]=0;
}

class MapiCE
{
public:
	LPMAPISESSION mSession;
	LPMDB mMsgStore;
	LPMAPIFOLDER mFolder;
	LPMAPITABLE mHierarchy;
	LPMAPITABLE mContentTable;	
	enum {
		ePR_SUBJECT,
		ePR_MESSAGE_DELIVERY_TIME,
		ePR_SENDER_EMAIL_ADDRESS,
		ePR_ENTRYID,
		NUM_COLS
		};
public:
	MapiCE(void)
	{
		mSession = NULL;
		mMsgStore = NULL;
		mFolder = NULL;
		mContentTable = NULL;
	}
public:
	~MapiCE(void)
	{
		MAPILogoff();
	}

public:
	bool MAPILogOn()
	{
		if(FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) 
			return FALSE;
		if (FAILED(MAPIInitialize(NULL)))
			return FALSE;
		if (FAILED(MAPILogonEx(0 ,NULL, NULL, 0, &mSession)))
			return FALSE;
		return true;
	}

public:
	bool MAPILogoff()
	{
		RELEASE(mContentTable);
		RELEASE(mFolder);
		RELEASE(mMsgStore);

		if(mSession)
		{
			mSession->Logoff(0, 0, 0);
			mSession->Release();
		}
		MAPIUninitialize();
		CoUninitialize();
		return true;
	}
public:
	HRESULT GetMsgStore(LPCTSTR FolderName)
	{
		HRESULT hr = S_OK;
		mSession->GetMsgStoresTable(MAPI_UNICODE, &mHierarchy);
		// next we loop over the message stores opening each msgstore and
		// getting its name to see if the name matches SMS.
		// If it does then we break out of the loop
		while (SUCCEEDED(hr))
		{
			SRowSet* pRowSet = NULL;
			hr = mHierarchy->QueryRows(1, 0, &pRowSet);

			// If we failed to query the
			// rows then we need to break
			if (FAILED(hr))
				break;

			// if we got no rows back then just exit the loop
			//remembering to set an error
			if (pRowSet->cRows == 1)
			{
				ASSERT(pRowSet->aRow[0].lpProps->ulPropTag == PR_ENTRYID);
				SBinary& blob = pRowSet->aRow[0].lpProps->Value.bin;
				hr = mSession->OpenMsgStore(NULL, blob.cb, (LPENTRYID)blob.lpb, NULL, 0, &mMsgStore);
				if (FAILED(hr))
					break;
			}
			else
			{
				hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
				break;
			}

			// now remember to free the row set
			FreeProws(pRowSet);
			if (FAILED(hr))
				break;

			// now get the display name property from the
			// message store to compare it against the name
			// 'SMS'
			SPropTagArray props;
			props.cValues = 1;
			props.aulPropTag[0] = PR_DISPLAY_NAME;

			ULONG cValues;
			SPropValue* pProps = NULL;
			hr = mMsgStore->GetProps(&props, MAPI_UNICODE, &cValues, &pProps);
			if (FAILED(hr) || cValues != 1)
				break;

			// if the name matches FolderName then break and as
			// hr == S_OK the current MsgStore smart pointer
			// will correctly be set.
			if (_tcsicmp(pProps[0].Value.lpszW, FolderName) == 0)
				break;
		}
		if (FAILED(hr))
			RELEASE(mMsgStore);
		return hr;
	}

public:
	HRESULT GetInboxFolder()
	{
		// Now get the Drafts folder.
		SPropTagArray propDefaultFolder;
		propDefaultFolder.cValues = 1;
		propDefaultFolder.aulPropTag[0] = PR_CE_IPM_INBOX_ENTRYID ;

		ULONG			cValues;
		LPSPropValue	pPropVals;
		HRESULT hr = mMsgStore->GetProps (&propDefaultFolder, MAPI_UNICODE, &cValues, &pPropVals);
		if (SUCCEEDED(hr))
		{
			SBinary& eidDrafts = pPropVals->Value.bin;
			hr = mMsgStore->OpenEntry(eidDrafts.cb, (LPENTRYID)eidDrafts.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&mFolder);
		}
		return hr;
	}

public:
	HRESULT DeleteMessage(SBinary *sbin)
	{
		HRESULT hr = S_OK;
		ENTRYLIST lst;
		lst.cValues = 1;
		lst.lpbin = sbin;
		hr = mFolder->DeleteMessages(&lst, NULL, NULL, 0); 
		return hr;
	}
public:
	HRESULT GetContentTable()
	{
		HRESULT hr = S_OK;
		SizedSPropTagArray(NUM_COLS,sptCols) = {NUM_COLS,
			PR_SUBJECT,
			PR_MESSAGE_DELIVERY_TIME,
			PR_SENDER_EMAIL_ADDRESS,
			PR_ENTRYID
		};

		hr = mFolder->GetContentsTable(0,&mContentTable);
		if (SUCCEEDED(hr))
		{
			hr = mContentTable-> SetColumns((LPSPropTagArray)&sptCols, 0);
		}
		return hr; 
	}
public:
	bool GetNextMessage(const FILETIME lFileTime,WCHAR *mBody,WCHAR *mNumber,FILETIME *mDateTime, bool mDelete)
	{
		LPSRowSet pRows = NULL;
		bool found =false;
		while (found==false && SUCCEEDED(mContentTable->QueryRows(1, 0, &pRows)) && pRows->cRows != 0 )
		{
			if (PR_MESSAGE_DELIVERY_TIME == pRows -> aRow[0].lpProps[ePR_MESSAGE_DELIVERY_TIME].ulPropTag)
			{
				if(CompareFileTime(&(pRows->aRow[0].lpProps[ePR_MESSAGE_DELIVERY_TIME].Value.ft),&lFileTime)>0)
				{
					found = true;
					*mDateTime = pRows->aRow[0].lpProps[ePR_MESSAGE_DELIVERY_TIME].Value.ft;
						//FileTimeToLocalFileTime(&(pRows->aRow[0].lpProps[ePR_MESSAGE_DELIVERY_TIME].Value.ft),mDateTime);
				}
				else
				{
					FreeProws(pRows);
					continue;
				}
			}
			if (PR_SUBJECT == pRows -> aRow[0].lpProps[ePR_SUBJECT].ulPropTag)
			{
				wsprintf(mBody,L"%s",pRows->aRow[0].lpProps[ePR_SUBJECT].Value.lpszW);
			}
			if (PR_SENDER_EMAIL_ADDRESS == pRows -> aRow[0].lpProps[ePR_SENDER_EMAIL_ADDRESS].ulPropTag)
			{
				wsprintf(mNumber, L"%s",pRows->aRow[0].lpProps[ePR_SENDER_EMAIL_ADDRESS].Value.lpszW);
			}
			if(mDelete && PR_ENTRYID == pRows -> aRow[0].lpProps[ePR_ENTRYID].ulPropTag)
			{
				DeleteMessage(&(pRows->aRow[0].lpProps[ePR_ENTRYID].Value.bin));
			}
			FreeProws(pRows);

		}
		return found;
	}
};
